#include "qmaingui.h"

void QMainGUI::createActions(void)
{
    newAction = new QAction(tr("New"),this);
    newAction->setObjectName("newAction");
    newAction->setShortcut(tr("Ctrl+N"));
    openAction = new QAction(tr("Open"),this);
    openAction->setObjectName("openAction");
    openAction->setShortcut(tr("Ctrl+O"));
    saveAction = new QAction(tr("Save"),this);
    saveAction->setObjectName("saveAction");
    saveAction->setShortcut(tr("Ctrl+S"));
    importAction = new QAction(tr("Import"),this);
    importAction->setObjectName("importAction");
    importAction->setShortcut(tr("Ctrl+I"));
    exportAction = new QAction(tr("Export"),this);
    exportAction->setObjectName("exportAction");
    exportAction->setShortcut(tr("Ctrl+E"));
    toggleModelAction = new QAction(tr("Run"),this);
    toggleModelAction->setObjectName("toggleModelAction");
    toggleModelAction->setShortcut(tr("Ctrl+T"));
    quitAction = new QAction(tr("Quit"),this);
    quitAction->setObjectName("quitAction");
    quitAction->setShortcut(tr("Ctrl+Q"));

    cellModeAction = new QAction(tr("Cell Mode"),this);
    cellModeAction->setIcon(QIcon(":/img/cell.png"));
    cellModeAction->setObjectName("cellModeAction");
    cellModeAction->setShortcut(tr("Alt+C"));
    nodeModeAction = new QAction(tr("Node Mode"),this);
    nodeModeAction->setIcon(QIcon(":/img/node.png"));
    nodeModeAction->setObjectName("nodeModeAction");
    nodeModeAction->setShortcut(tr("Alt+N"));
    edgeModeAction = new QAction(tr("Edge Mode"),this);
    edgeModeAction->setIcon(QIcon(":/img/edge.png"));
    edgeModeAction->setObjectName("edgeModeAction");
    edgeModeAction->setShortcut(tr("Alt+E"));
    areaModeAction = new QAction(tr("Area Mode"),this);
    areaModeAction->setIcon(QIcon(":/img/area.png"));
    areaModeAction->setObjectName("areaModeAction");
    areaModeAction->setShortcut(tr("Alt+A"));

    resetDefaultLengthsAction = new QAction(tr("Reset Default Lengths"),this);
    resetDefaultLengthsAction->setObjectName("resetDefaultLengthsAction");
    resetDefaultLengthsAction->setShortcut(tr("Alt+Ctrl+R"));
    generateNodesAction = new QAction(tr("Generate Nodes"),this);
    generateNodesAction->setObjectName("generateNodesAction");
    generateNodesAction->setShortcut(tr("Alt+Ctrl+G"));

    saveSvgAction = new QAction(tr("Save SVG"),this);
    saveSvgAction->setObjectName("saveSvgAction");
    saveSvgAction->setShortcut(tr("Alt+Ctrl+S"));
    savePngAction = new QAction(tr("Save PNG"),this);
    savePngAction->setObjectName("savePngAction");
    savePngAction->setShortcut(tr("Alt+Ctrl+P"));
    savePngsAction = new QAction(tr("Save PNGs for movie into ./mov/"),this);
    savePngsAction->setObjectName("savePngsAction");
    savePngsAction->setShortcut(tr("Alt+Ctrl+M"));
    savePngsAction->setCheckable(true);

    showNodeNumberAction = new QAction(tr("Show Node Numbers"),this);
    showNodeNumberAction->setObjectName("showNodeNumberAction");
    showNodeNumberAction->setShortcut(tr("Alt+1"));
    showNodeNumberAction->setCheckable(true);
    showEdgeNumberAction = new QAction(tr("Show Edge Numbers"),this);
    showEdgeNumberAction->setObjectName("showEdgeNumberAction");
    showEdgeNumberAction->setShortcut(tr("Alt+2"));
    showEdgeNumberAction->setCheckable(true);
    showAreaNumberAction = new QAction(tr("Show Area Numbers"),this);
    showAreaNumberAction->setObjectName("showAreaNumberAction");
    showAreaNumberAction->setShortcut(tr("Alt+3"));
    showAreaNumberAction->setCheckable(true);
    fieldModeAction = new QAction(tr("Vector Field"),this);
    fieldModeAction->setObjectName("fieldModeAction");
    fieldModeAction->setShortcut(tr("Alt+F"));

    monitorAdhAction = new QAction(tr("Track adhesion"),this);
    monitorAdhAction->setObjectName("monitorAdhAction");
    monitorAdhAction->setCheckable(true);
    monitorPolAction = new QAction(tr("Track polymerization"),this);
    monitorPolAction->setObjectName("monitorPolAction");
    monitorPolAction->setCheckable(true);
    monitorConAction = new QAction(tr("Track contraction"),this);
    monitorConAction->setObjectName("monitorConAction");
    monitorConAction->setCheckable(true);
    monitorElaAction = new QAction(tr("Track elasticity"),this);
    monitorElaAction->setObjectName("monitorElaAction");
    monitorElaAction->setCheckable(true);
}

void QMainGUI::createMenus(void)
{
    fileMenu = menuBar()->addMenu(tr("File"));
    fileMenu->addAction(newAction);
    fileMenu->addAction(openAction);
    fileMenu->addAction(saveAction);
    fileMenu->addSeparator();
    fileMenu->addAction(importAction);
    fileMenu->addAction(exportAction);
    fileMenu->addSeparator();
    fileMenu->addAction(toggleModelAction);
    fileMenu->addSeparator();
    fileMenu->addAction(quitAction);

    modeMenu = menuBar()->addMenu(tr("Mode"));
    modeMenu->addAction(cellModeAction);
    modeMenu->addAction(nodeModeAction);
    modeMenu->addAction(edgeModeAction);
    modeMenu->addAction(areaModeAction);

    editMenu = menuBar()->addMenu(tr("Edit"));
    editMenu->addAction(resetDefaultLengthsAction);
    editMenu->addAction(generateNodesAction);

    toolMenu = menuBar()->addMenu(tr("Tool"));
    toolMenu->addAction(saveSvgAction);
    toolMenu->addAction(savePngAction);
    toolMenu->addAction(savePngsAction);

    viewMenu = menuBar()->addMenu(tr("View"));
    viewMenu->addAction(showNodeNumberAction);
    viewMenu->addAction(showEdgeNumberAction);
    viewMenu->addAction(showAreaNumberAction);
    viewMenu->addSeparator();
    viewMenu->addAction(fieldModeAction);
    this->menuBar()->addSeparator();

    monitorMenu = menuBar()->addMenu(tr("Monitor"));
    monitorMenu->addAction(monitorAdhAction);
    monitorMenu->addAction(monitorPolAction);
    monitorMenu->addAction(monitorConAction);
    monitorMenu->addAction(monitorElaAction);
}

void QMainGUI::createToolBars(void)
{
    QToolBar *fileToolBar = new QToolBar("File ToolBar", this);
    fileToolBar->addAction(newAction);
    fileToolBar->addAction(openAction);
    fileToolBar->addAction(saveAction);
    fileToolBar->addAction(importAction);
    fileToolBar->addAction(exportAction);
    fileToolBar->addAction(toggleModelAction);
    this->addToolBar(Qt::LeftToolBarArea, fileToolBar);

    QToolBar *modeToolBar = new QToolBar("Mode ToolBar", this);
    modeToolBar->addAction(cellModeAction);
    modeToolBar->addAction(nodeModeAction);
    modeToolBar->addAction(edgeModeAction);
    modeToolBar->addAction(areaModeAction);
    this->addToolBar(Qt::LeftToolBarArea, modeToolBar);
}

void QMainGUI::createStatusBar(void)
{
    modeLabel = new QLabel(this);
    this->statusBar()->addPermanentWidget(modeLabel);

    currentStateLabel = new QLabel(this);
    this->statusBar()->addPermanentWidget(currentStateLabel);
}

QMainGUI::QMainGUI(QMainCanvas *_canvas, QMainCore *_core, QWidget *parent): QMainWindow(parent), canvas(_canvas), core(_core)
{
    canvas->resize(10000, 10000);
    area = new QScrollArea(this);
    area->setWidget(canvas);
    //canvas->setParent(area);

    connect(area->verticalScrollBar(), SIGNAL(valueChanged(int)), canvas, SLOT(update()));
    connect(area->horizontalScrollBar(), SIGNAL(valueChanged(int)), canvas, SLOT(update()));
    recordTimer = new QTimer;
    connect(recordTimer, SIGNAL(timeout()), this, SLOT(savePngSlot()));

    this->setCentralWidget(area);

    this->createActions();
    this->createMenus();
    this->createToolBars();
    this->createStatusBar();

    this->setWindowTitle(tr("2D Cell Motility Model"));
    this->on_cellModeAction_triggered();
    this->externalToggleModelSlot();
    this->resize(800,600);

    QMetaObject::connectSlotsByName(this);
}

QMainGUI::~QMainGUI()
{
    core->stop();
}

void QMainGUI::on_newAction_triggered(void)
{
    if (!core->isRunning())
    {
        core->reset();
    }
}

void QMainGUI::on_openAction_triggered(void)
{
    QString fileName = QFileDialog::getOpenFileName(this, "Select model to open", QString(), "*.xml");
    if (!fileName.isEmpty())
    {
        core->reset();
        QFile file(fileName);

        QXmlInputSource xmlInputSource(&file);
        QModelSaver saver;
        QXmlSimpleReader xmlSimpleReader;
        xmlSimpleReader.setContentHandler(&saver);
        xmlSimpleReader.parse(xmlInputSource);

        file.close();

        core->setCell(saver.getCell());
        statusBar()->showMessage(tr("Model opened"), 2000);
    }
}

void QMainGUI::on_saveAction_triggered(void)
{
    QString fileName = QFileDialog::getSaveFileName(this, "Save Model As",
                                                    QDateTime().currentDateTime().toString("dd.MM.yyyy-hh.mm.ss.zzz") + ".xml", "*.xml");
    if (!fileName.isEmpty())
    {
        QModelSaver saver;
        saver.saveXmlModel(core->getCell(), fileName);
        statusBar()->showMessage(tr("Model saved"), 2000);
    }
}

void QMainGUI::on_importAction_triggered(void)
{
    QString fileName = QFileDialog::getOpenFileName(this, "Import Model As", QString(), "*.nodes");
    if (!fileName.isEmpty())
    {
        QModelSaver saver;
        saver.importPlainTextModel(fileName);

        core->setCell(saver.getCell());
        core->resetDefaultLengths();
        statusBar()->showMessage(tr("Model imported"), 2000);
    }
}

void QMainGUI::on_exportAction_triggered(void)
{
    QString fileName = QFileDialog::getSaveFileName(this, "Export Nodes As", "data.nodes", "*.nodes");
    if (!fileName.isEmpty())
    {
        QModelSaver saver;
        saver.exportPlainTextModel(core->getCell(), fileName);

        statusBar()->showMessage(tr("Model exported"), 2000);
    }
}

void QMainGUI::on_toggleModelAction_triggered(void)
{
    if (core->isRunning())
    {
        core->stop();
        toggleModelAction->setText(tr("Run"));
        currentStateLabel->setText(tr("Stopped"));
    }
    else
    {
        core->start();
        toggleModelAction->setText(tr("Stop"));
        currentStateLabel->setText(tr("Running"));
    }
}

void QMainGUI::on_quitAction_triggered(void)
{
    core->stop();
    this->close();
}

void QMainGUI::on_cellModeAction_triggered()
{
    canvas->setMode(00);
    modeLabel->setText(tr("Cell edit mode"));
    statusBar()->showMessage(tr("Mode changed"), 2000);
}

void QMainGUI::on_nodeModeAction_triggered()
{
    canvas->setMode(10);
    modeLabel->setText(tr("Node edit mode"));
    statusBar()->showMessage(tr("Mode changed"), 2000);
}

void QMainGUI::on_edgeModeAction_triggered()
{
    canvas->setMode(20);
    modeLabel->setText(tr("Edge edit mode"));
    statusBar()->showMessage(tr("Mode changed"), 2000);
}

void QMainGUI::on_areaModeAction_triggered()
{
    canvas->setMode(30);
    modeLabel->setText(tr("Area edit mode"));
    statusBar()->showMessage(tr("Mode changed"), 2000);
}

void QMainGUI::on_resetDefaultLengthsAction_triggered(void)
{
    core->resetDefaultLengths();
    statusBar()->showMessage(tr("Default lengths of the edges were reseted"), 2000);
}

void QMainGUI::on_generateNodesAction_triggered(void)
{
    if (!core->isRunning())
    {
        CELL cell;
        double R = 125;
        double N = 100000;
        QPointF shift(R+20,R+20);

        double r, phi;

        qsrand(QTime().currentTime().second());
        for (int i=0; i<N; ++i)
        {
            phi = 2*M_PI*i/N;
            core->addNode(QPointF(R*cos(phi), R*sin(phi))+shift);
        }

        for (int i=0; i<N; ++i)
        {
            r = sqrt(R*R*static_cast<double>(qrand())/RAND_MAX);
            phi = 2*M_PI*static_cast<double>(qrand())/RAND_MAX;

            core->addNode(QPointF(r*cos(phi), r*sin(phi))+shift);
        }

        //core->setCell(cell);
    }
}

void QMainGUI::on_saveSvgAction_triggered(void)
{
    QString fileName = QFileDialog::getSaveFileName(this, tr("Save SVG"), tr("image.svg"), tr("SVG Files (*.svg)"));

    if (!fileName.isEmpty())
    {
        canvas->saveSvg(fileName);
        statusBar()->showMessage(tr("SVG saved"), 2000);
    }

}

void QMainGUI::on_savePngAction_triggered(void)
{
    this->savePngSlot();
    statusBar()->showMessage(tr("PNG saved"), 2000);
}

void QMainGUI::on_savePngsAction_triggered(void)
{
    //ffmpeg -i %05d.png -sameq movie.avi
    //for converting a set of images into a movie
    if (!recordTimer->isActive())
    {
        recordedImagesCounter = 0;
        int msec = QInputDialog::getInt(this, tr("Enter desired frame interval"), tr("Milliseconds:"), 100, 1);
        recordTimer->setInterval(msec);
        recordTimer->start();

        savePngsAction->setChecked(true);
        statusBar()->showMessage(tr("Record started"), 2000);
    }
    else
    {
        recordTimer->stop();
        savePngsAction->setChecked(false);
        statusBar()->showMessage(tr("Record finished"), 2000);
    }
}

void QMainGUI::on_showNodeNumberAction_triggered(bool showNodeNumber)
{
    canvas->setShowNodeNumber(showNodeNumber);
}

void QMainGUI::on_showEdgeNumberAction_triggered(bool showEdgeNumber)
{
    canvas->setShowEdgeNumber(showEdgeNumber);
}

void QMainGUI::on_showAreaNumberAction_triggered(bool showAreaNumber)
{
    canvas->setShowAreaNumber(showAreaNumber);
}

void QMainGUI::on_fieldModeAction_triggered(void)
{
    if (fieldModeAction->text().contains(tr("Vector Field")))
    {
        fieldModeAction->setText(tr("Color Field"));
    }
    else
    {
        fieldModeAction->setText(tr("Vector Field"));
    }
    this->toggleCanvasFieldMode();
}

void QMainGUI::toggleCanvasFieldMode(void)
{
    if(monitorAdhAction->isChecked()||monitorPolAction->isChecked()||
       monitorConAction->isChecked()||monitorElaAction->isChecked())
    {
        if (fieldModeAction->text().contains(tr("Vector Field")))
        {
            canvas->setVectorFieldMode(true);
            canvas->setColorFieldMode(false);
        }
        else if (fieldModeAction->text().contains(tr("Color Field")))
        {
            canvas->setVectorFieldMode(false);
            canvas->setColorFieldMode(true);
        }
    }
    else
    {
        canvas->setVectorFieldMode(false);
        canvas->setColorFieldMode(false);
    }
}

void QMainGUI::on_monitorAdhAction_triggered(bool trackAdh)
{
    core->setTrackAdh(trackAdh);
    this->toggleCanvasFieldMode();
}

void QMainGUI::on_monitorPolAction_triggered(bool trackPol)
{
    core->setTrackPol(trackPol);
    this->toggleCanvasFieldMode();
}

void QMainGUI::on_monitorConAction_triggered(bool trackCon)
{
    core->setTrackCon(trackCon);
    this->toggleCanvasFieldMode();
}

void QMainGUI::on_monitorElaAction_triggered(bool trackEla)
{
    core->setTrackEla(trackEla);
    this->toggleCanvasFieldMode();
}

void QMainGUI::externalToggleModelSlot(void)
{
    if (core->isRunning())
    {
        toggleModelAction->setText(tr("Stop"));
        currentStateLabel->setText(tr("Running"));
    }
    else if (!core->isRunning())
    {
        toggleModelAction->setText(tr("Run"));
        currentStateLabel->setText(tr("Stopped"));
    }
}

void QMainGUI::savePngSlot(void)
{
    QPixmap pixmap = QPixmap::grabWidget(this, 0, 26, this->width(), this->height()-26);

    QString dirName("mov/");
    QDir dir;
    if (!dir.exists(dirName)) dir.mkdir(dirName);

    if (!savePngsAction->isChecked())
    {
        QString fileName = QFileDialog::getSaveFileName(this, tr("Save PNG Image"),
                                                        QDateTime().currentDateTime().toString("dd.MM.yyyy-hh.mm.ss.zzz") + ".png", tr("PNG Files (*.png)"));
        if (!fileName.isEmpty()) pixmap.save(fileName, "png");
    }
    else
    {
        if (recordedImagesCounter<10) pixmap.save(dirName + "/0000"+QString::number(recordedImagesCounter)+".png", "png");
        else if (recordedImagesCounter<100) pixmap.save(dirName + "/000"+QString::number(recordedImagesCounter)+".png", "png");
        else if (recordedImagesCounter<1000) pixmap.save(dirName + "/00"+QString::number(recordedImagesCounter)+".png", "png");
        else if (recordedImagesCounter<10000) pixmap.save(dirName + "/0"+QString::number(recordedImagesCounter)+".png", "png");
        else pixmap.save(dirName + QString::number(recordedImagesCounter)+".png", "png");

        recordedImagesCounter++;
    }
}
